import pygame
from dude import creep_c
#from scipy import weave

#main gui class
"""
todo:
need to be able to trap all mouse events if completely in an item or share them out if across 2.
make sure you can layer gui items, that's how i'll prolly be doing the menu.

Might be worthwhile being able to set a height for a gui item for mouse click catching.  ie i could chuck the map browser at the top level so it overlays the playfield
"""
class gui_c:
    #area is a pygame.rect, surface is the surface to draw this gui item on
    def __init__(self, area, game, guiName):
        #area is the actual area on the surface that this gui item can draw on:  set as x,y,width,height
        self.area = area
        self.surface = game.screen
        self.dirty = False
        self.redrawAreas = []
        self.guiName = guiName

    #add an area to redraw for this gui item, all redraw areas will be redrawn when the draw is called on this item
    #only these areas will be redrawn, not the entire item.
    def addRedrawArea(self, area):
        #need some code here to test for overlapping areas
        self.redrawAreas += [area]
        self.dirty = True
    
    def checkMouse(self, mouse):
        #check the redraw on the mouse pointer
        self.checkArea(mouse.area)
        if mouse.buttonDown and self.area.collidepoint(mouse.pos):
            self.click(mouse)
    
    #check if the checkArea is on this gui item
    def checkArea(self, checkArea):
        if self.area.colliderect(checkArea):
            self.addRedrawArea(checkArea)
            return True

    #click func: always override
    def click(self, mouse):
        print self.guiName + " clicked."

    #always override, prolly don't need this
    def mouseOver(self, mouse):
        #print "mover"
        pass

    #does the stuff required if this item is dirty
    def checkDirty(self):
        if self.dirty:
            self.surface.set_clip(self.area)
            self.draw()
            self.dirty = False

    #draw, needs to also be able to restore the previous surface state.
    def draw(self):
        #redraw all the redraw areas on this surface
        for redrawArea in self.redrawAreas:
            pygame.draw.rect(self.surface, (0,0,0), redrawArea, 0)
        self.redrawAreas=[]

#create an area to just repaint black
class blankArea_c(gui_c):
    def __init__(self, area, game, guiName):
        gui_c.__init__(self, area, game, guiName)

    def draw(self):
        #redraw all the redraw areas on this surface
        for redrawArea in self.redrawAreas:
            pygame.draw.rect(self.surface, (50,50,50), redrawArea, 0)
        self.redrawAreas=[]

#class mapBrowser
class mapBrowser_c(gui_c):
    def __init__(self, area, game):
        gui_c.__init__(self, area, game, "Map Browser")
        #probably don't want this here, but req at the moment.
        self.gameObj = game

    def checkArea(self, checkArea):
        if self.area.colliderect(checkArea):
            self.addRedrawArea(checkArea)

    def draw(self):
        #redraw all the redraw areas on this surface
        #for redrawArea in self.redrawAreas:
        #    pygame.draw.rect(self.surface, (50,50,50), redrawArea, 0)
        #self.redrawAreas=[]
        
        #blank the browser area
        pygame.draw.rect(self.surface, (0,0,0), self.area, 0)
        browserString = ""
        yOffset=0
        bittyHeight = 0
        
        for map in self.gameObj.maps:
            mapNameSurface=self.gameObj.writeText(map.title, (200,200,200))
            if bittyHeight == 0:
                bittyHeight=mapNameSurface.get_height()
            self.surface.blit(mapNameSurface, (0,yOffset))
            
            yOffset+=bittyHeight
        #self.surface.draw(mapNameSurface, )

#gameArea gui item, needs some speed optimising
class gameArea_c(gui_c):
    def __init__(self, area, game):
        gui_c.__init__(self, area, game, "Game Area")
        self.gameObj = game
        self.screenOffset = (0,0)
        self.viewPortalSize = game.viewPortalSize
        self.drawRect = area
        
    def click(self, mouse):
        crntPlayer=self.gameObj.crntPlayer
        
        crntPlayer.reqAction = crntPlayer.clickAction
        crntPlayer.mouse = mouse.getPos()
        #need to do view area offsetting here, but what about remote players?

    def checkDirty(self):
        self.surface.set_clip(self.area)
        self.draw()

    def draw(self):
        #set up the creep's redraw area so the first creep will always be bigger than it
        self.drawRect=[self.viewPortalSize[0],self.viewPortalSize[1],0,0]

        #get the game area offset from the mover and redraw the whole area, need to probably reduce this to the bits that need redrawing in future, this is fast enough atm
        self.screenOffset = self.gameObj.mover.getMapLoc()
        self.surface.blit(self.gameObj.crntMap.mapSurface, (0,0), (self.screenOffset[0],self.screenOffset[1], self.viewPortalSize[0], self.viewPortalSize[1]))
        
        #redraw areas in the redraw array, mouse, explosions, other stuff like traps, exits, entrances, not the guys though
        for redrawArea in self.redrawAreas:
            self.surface.blit(self.gameObj.crntMap.mapSurface, (redrawArea[0], redrawArea[1]), (redrawArea[0]+self.screenOffset[0],redrawArea[1]+self.screenOffset[1], redrawArea[2],redrawArea[3]))

        self.redrawAreas=[]
        self.gameObj.crntMap.drawExits(self.screenOffset)
        
        ### LOOP THE CREEPS ###
        for player in self.gameObj.players:
            ### SPAWN CREEPS ###
            if player.checkSpawn():
                spawnEntrance = player.getNextEntrance()
                sL = spawnEntrance.getSpawnLoc()
                newCreep = creep_c(sL[0], sL[1], spawnEntrance.direction, player, self.gameObj.crntMap.mapSurface, self.gameObj.anim, self.gameObj)
                player.addCreep(newCreep)
            
            #move the creeps and check the mouse against them in the same loop
            creepNum = 0
            while creepNum < len(player.creeps):
                creep = player.creeps[creepNum]
                #check the exits to see if this creep has done a runner
                creepExit = self.gameObj.crntMap.checkExits(creep.x, creep.y)
                #if there's an exit on this creep and the creep isn't already exiting.  Should probably be a reqChangeAction
                if creepExit != None and creep.action != 6:
                    creepExit.player.incScore()
                    creep.changeAction(6)

                #check the mouse click against creeps, might wanna get the one closest to centre
                if player.reqAction != None:
                    #should probably be able to ask the creep directly if it was clicked on
                    if creep.action != player.reqAction and creep.x > player.mouse[0] - 16 + self.screenOffset[0] and creep.x<player.mouse[0] + 16 + self.screenOffset[0] and creep.y>player.mouse[1] - 16 + self.screenOffset[1] and creep.y<player.mouse[1] + 16 + self.screenOffset[1]:
                        #if this action failed on this creep, keep trying it other creeps, else remove it
                        if creep.reqChangeAction(player.reqAction):
                            #self.logFile.write(str(self.framesDrawn) +" - Player " + player.name + " Changed creep: " + str(creep.number) +"\n")
                            player.reqAction=None

                #number the creep
                text = self.gameObj.writeText(player.name, (200, 200, 200))
                self.gameObj.screen.blit(text, (creep.x-2-self.screenOffset[0], creep.y-35-self.screenOffset[1]))
                
                creep.move()
                creep.draw(self.screenOffset)
            
                #grab the top left and bottom right creep's x and y for a redraw area
                #only needs to redraw what's onscreen, so make sure it won't go past screen area (to do)
                if creep.x<self.drawRect[0]:
                    self.drawRect[0]=creep.x
                if creep.x>self.drawRect[2]:
                    self.drawRect[2]=creep.x
                if creep.y<self.drawRect[1]:
                    self.drawRect[1]=creep.y
                if creep.y>self.drawRect[3]:
                    self.drawRect[3]=creep.y
                
                #if the creep is dead, remove it which will move the next one back, else move forward
                if creep.dead:
                    del player.creeps[creepNum]
                else:
                    creepNum+=1
            player.reqAction=None

        #draw other objects.  all moving objects should probably inherit from this class, but they don't
        for object in self.gameObj.objects:
            object.move()
            object.draw()    

        self.gameObj.crntMap.drawEntrances(self.screenOffset)

"""
map mover class, holds the scrolled pos of the screen, draws the minimap and allows it to scroll the big map
"""
class mapMover_c(gui_c):
    def __init__(self, area, mapImage, game):
        gui_c.__init__(self, area, game, "Map Mover")
        
        self.viewPortalSize = game.viewPortalSize
        self.game = game
        
        mapSize = (mapImage.get_width(), mapImage.get_height())

        #figure out which aspect has to be reduced further and then reduce the whole image that much to maintain ratio
        if area[2]!=0 and area[3]!=0:
            
            if float(area[2])/float(mapSize[0]) < float(area[3])/float(mapSize[1]):
                self.scaleRatio = float(area[2])/float(mapSize[0])
                self.area[3] = mapSize[1]*self.scaleRatio
            else:
                self.scaleRatio = float(area[3])/float(mapSize[1])
                self.area[2] = mapSize[1]*self.scaleRatio
        else:
            print "Illegal map mover size"
            self.scaleRatio=1

        #create a new map image for the mover object
        self.mapImage = pygame.transform.scale(mapImage, (int(mapSize[0]*self.scaleRatio), int(mapSize[1]*self.scaleRatio)))
        
        #set the size of the view-region showing box
        #should grab nice whole number widths and heights so the box doesn't fuck around later, but it doesn't
        #this should prolly be pygame.rect
        self.boxSize = (self.viewPortalSize[0] * self.scaleRatio, self.viewPortalSize[1] * self.scaleRatio)
        
        #reset the screen position
        self.screenPos = (0, 0)

    #this one just redraws all of itself
    def addRedrawArea(self, area):
        self.dirty=True

    #always redraws if it's checked
    def checkDirty(self):
        self.surface.set_clip(self.area)
        self.draw()
    
    #on click, move the view area in the main screen and redraw the view area box on the map
    def click(self, mouse):
        pos=[0,0]
        pos[0],pos[1]=mouse.pos[0]-self.area[0],mouse.pos[1]-self.area[1]

        #if the new scroll X pos is bigger than the screen, then make it the edge, etc
        if pos[0] + self.boxSize[0] / 2 > self.area[2]:
            pos[0] = self.area[2] - self.boxSize[0] / 2
        
        if pos[0] - self.boxSize[0] / 2 < 0:
            pos[0] = self.boxSize[0] / 2

        if pos[1] + self.boxSize[1] / 2 > self.area[3]:
            pos[1] = self.area[3] - self.boxSize[1] / 2
        
        if pos[1] - self.boxSize[1] / 2 < 0:
            pos[1] = self.boxSize[1] / 2

        #set the scroll amounts, div by 2 to get the center of the box
        self.screenPos = (pos[0] - self.boxSize[0] / 2, pos[1] - self.boxSize[1] / 2)

    #just return the x,y of the top left of the view area relative to 0,0 for the map's image, upsize the co-ords to real size.  Might not be too exact
    def getMapLoc(self):
        return (self.screenPos[0] / self.scaleRatio, self.screenPos[1] / self.scaleRatio)
    
    def draw(self):
        #blank the minimap area
        pygame.draw.rect(self.surface, (0,0,0), self.area, 0)
        #draw the minimap
        self.surface.blit(self.mapImage, self.area)
        #draw the outline box
        pygame.draw.rect(self.surface, (255,255,255), self.area, 1)
        #draw the viewarea box
        pygame.draw.rect(self.surface, (200,200,200), (self.screenPos[0] + self.area[0], self.screenPos[1] + self.area[1], self.boxSize[0], self.boxSize[1]), 1)

"""
draws the action menu.
"""
class actionMenu_c(gui_c):
    def __init__(self, area, menuImage, gameObj):
        gui_c.__init__(self, area, gameObj, "Action Menu")
        
        self.buttonSize = (32,48)
        self.menuImage = menuImage
        self.gameObj = gameObj
        self.selectedButton = 0
    
    #this one just redraws all of itself
    def addRedrawArea(self, area):
        self.dirty = True

    def checkDirty(self):
        self.surface.set_clip(self.area)
        self.draw()
            
    def click(self, mouse):
        self.selectedButton = mouse.pos[0] / self.buttonSize[0]
        self.gameObj.crntPlayer.clickAction = self.gameObj.menuActions[self.selectedButton]
        print self.gameObj.crntPlayer.clickAction
    
    def draw(self):
        self.surface.blit(self.menuImage, (self.area[0], self.area[1]))
        pygame.draw.rect(self.surface, (255,255,255), (self.buttonSize[0]*(self.selectedButton)+self.area[0], self.area[1], self.buttonSize[0], self.buttonSize[1]), 1)
